from MMU import *
from decoder import type, sign_expend


def MEM(wb: bit_64, addr: bit_64, content: bit_64, rd, job: type, mem: memory, mmu: MMU):
    if job.do == 1 or job.do == 2:
        phy_addr = mmu.to_phy_addr(addr.val, 2 if ((addr.val >> 20) > 0) else 1, mem)
        if job.do == 1:
            if job.size == 0:
                mem.data_64_port_in(content.val, phy_addr)
            elif job.size == 1:
                mem.data_32_port_in(content.val & 0xffffffff, phy_addr)
            elif job.size == 2:
                mem.data_16_port_in(content.val & 0xffff, phy_addr)
            elif job.size == 3:
                mem.data_8_port_in(content.val & 0xff, phy_addr)
#            print("MEM: [%d] = %d" % (phy_addr, content.val))
        else:
            job.wb = True
            if job.size == 0:
                wb = bit_64(mem.data_64_port_out(phy_addr))
            elif job.size == 1:
                if job.unsigned:
                    wb = bit_64(mem.data_32_port_out(phy_addr))
                else:
                    wb = bit_64(sign_expend(mem.data_32_port_out(phy_addr), 32))
            elif job.size == 2:
                if job.unsigned:
                    wb = bit_64(mem.data_16_port_out(phy_addr))
                else:
                    wb = bit_64(sign_expend(mem.data_16_port_out(phy_addr), 16))
            elif job.size == 3:
                if job.unsigned:
                    wb = bit_64(mem.data_8_port_out(phy_addr))
                else:
                    wb = bit_64(sign_expend(mem.data_8_port_out(phy_addr), 8))

#            print("MEM: x%d = [%d] = %d" % (rd, phy_addr, wb.val))
#    else:
#        print("MEM: NOP")

    return wb, rd, job

